{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Interactive kinetic modelling\n",
    "In this notebook we will look at how we can explore a simple kinetic system using only\n",
    "a handful of lines of Python code and the ChemPy library. First we import the functions & classes\n",
    "that we will be using:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from collections import defaultdict\n",
    "from ipywidgets import interact, FloatSlider\n",
    "from chempy import ReactionSystem, Substance\n",
    "from chempy.kinetics.ode import get_odesys\n",
    "from chempy.kinetics._native import get_native\n",
    "from chempy.units import SI_base_registry, default_units as u\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next we define our what reactions are taking place:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rsys = ReactionSystem.from_string(\"\"\"\n",
    "A -> B; 'k1'\n",
    "B + C -> P; 'k2'\n",
    "\"\"\", substance_factory=Substance)\n",
    "rsys"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "From this reactionsystem we generate a system of ordinary differential equations:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "odesys, extra = get_odesys(rsys, include_params=False, unit_registry=SI_base_registry,\n",
    "                           output_conc_unit=u.micromolar, output_time_unit=u.minute)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Not that it is strictly needed for this simple system, but since we are using [pyodesys](https://github.com/bjodah/pyodes), we can generate C++ code which is compiled to a native\n",
    "extension module:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "native = get_native(rsys, odesys, 'cvode')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We will use ipywidgets for our interactive controls:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def integrate_and_plot(\n",
    "    tend_minutes=FloatSlider(5, min=1, max=60, step=1),\n",
    "    lgA0molar=FloatSlider(-6, min=-7, max=-5, step=.1),\n",
    "    lgC0molar=FloatSlider(-6, min=-7, max=-5, step=.1),\n",
    "    k1_per_min=FloatSlider(5.8, min=1.0, max=20.0, step=0.1),\n",
    "    k2_per_M_per_s=FloatSlider(4000, min=500, max=16000, step=500)\n",
    "):\n",
    "    result = native.integrate(tend_minutes*u.minute, defaultdict(lambda: 0*u.M, {'A': 10**lgA0molar*u.M, 'C': 10**lgC0molar*u.M}),\n",
    "                              {'k1': k1_per_min/u.minute, 'k2': k2_per_M_per_s/u.M/u.s}, integrator='cvode')\n",
    "    result.plot(title_info=2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Try exploring the system by adjusting the parameter sliders below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "interact(integrate_and_plot)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  },
  "widgets": {
   "state": {
    "eea5f566c0464c47a714f316bff761ef": {
     "views": [
      {
       "cell_index": 5
      }
     ]
    }
   },
   "version": "1.2.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
